package com.javaex.book.resolver;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.BeanUtils;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import com.javaex.book.utils.JsonUtils;

public class JsonRequestParamMethodArgumentResolver implements HandlerMethodArgumentResolver {
	
	static final String APPLICATION_JSON = "application/json";
	static final String REQUEST_ATTRIBUTE_KEY = "REQUEST_JSON_PARAM_MAP_IN_ATTRIBUTE_KEY";

	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		// 判断参数类型是不是简单类型，如果不是，获取参数值还是使用 @RequestBody 吧
		return BeanUtils.isSimpleProperty(parameter.getNestedParameterType());
	}

	@Override
	public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
			WebDataBinderFactory binderFactory) throws Exception {
		HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
		// 判断请求参数编码类型是不是 application/json
		if (!request.getContentType().contains(APPLICATION_JSON)) {
			return null;
		}
		
		// 从请求域中获取解析好的json数据。如果不存在，从请求中获取
		@SuppressWarnings("unchecked")
		Map<String, Object> map = (Map<String, Object>) request.getAttribute(REQUEST_ATTRIBUTE_KEY);
		if (map == null) {
			// 从请求中读取json字符串
			BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
			
			// 解析json字符串为Map，并添加到请求域中
			map = JsonUtils.parseToMap(reader.readLine());
			webRequest.setAttribute(REQUEST_ATTRIBUTE_KEY, map, RequestAttributes.SCOPE_REQUEST);
		}
		if (map == null) return null;
		
		Object value = map.get(parameter.getParameterName());
		// 类型转换
		if (binderFactory != null) {
			WebDataBinder binder = binderFactory.createBinder(webRequest, null, parameter.getParameterName());
			value = binder.convertIfNecessary(value, parameter.getParameterType());
		}
		return value;
	}

	
}
